; Disassembly of the file "z:\ramdisk\home\knoppix\none\CPM_KRYSS_Loader.bin" ; ; CPU Type: Z80 ; ; Created with dZ80 2.0 ; ; on Sunday, 14 of October 2012 at 06:55 PM ; 0000 00 NOP 0001 00 NOP 0002 00 NOP 0003 3E00 LD A,00 0005 D3FE OUT ($FE),A ; SO=0, O6=0 (DRAM#1 CPU access), O5=0, border=black 0007 211600 LD HL,$0016 ; copy rest of 000a 1100FC LD DE,$FC00 ; this code 000d 010004 LD BC,$0400 ; from 0016 0010 EDB0 LDIR ; to FC00 0012 C325FC JP $FC25 ; run copied code from FC25 (003B in this code) 0015 00 DB $00 ORG FC00 ; next line at FC00 after copying 0016 7F DB $7F ; (FC00) CTC0 vector \ CTC INT. ROUTINE #2 0017 FC DB $FC ; (FC01) CTC0 vector / (does nothing) 0018 7F DB $7F ; (FC02) CTC1 vector \ CTC INT. ROUTINE #2 0019 FC DB $FC ; (FC03) CTC1 vector / (does nothing) 001A 72 DB $72 ; (FC04) CTC2 vector \ CTC INT. ROUTINE #1 001B FC DB $FC ; (FC05) CTC2 vector / (replaces CTC0 vector with CTC1 vector) 001C 7F DB $7F ; (FC06) CTC3 vector \ CTC INT. ROUTINE #2 001D FC DB $FC ; (FC07) CTC3 vector / (does nothing) 001E 00 DB $00 ; (FC08) used as flag: =00 right before & during track reading, =FF after 001F 00 DB $00 ; (FC09) \ storage start address 0020 00 DB $00 ; (FC0A) / for data read from disk (0000 initially) 0021 00 DB $00 ; (FC0B) \ storage start address for the second system track 0022 24 DB $24 ; (FC0C) / (18 sectors * 512 bytes = 12h*200h = 2400h) 0023 00 DB $00 ; (FC0D) \ current storage address 0024 00 DB $00 ; (FC0E) / for data read from disk 0025 00 DB $00 ; (FC0F) time constant for CTC channel 1 (256 bytes to read) 0026 24 DB $24 ; (FC10) time constant for CTC channel 2 (24=2*12 -> 2*12h*256=12h*512=18 sectors=1 track both sides) 0027 EF DB $EF ; (FC11) \ these 2 bytes are arguments for a Specify command 0028 FF DB $FF ; (FC12) / (SRT=E=2ms, HUT=F=240ms, HLT=7F=254ms, ND=1->Non-DMA mode) 0029 00 DB $00 ; (FC13) arg#1: Side, Drive No. 002A 00 DB $00 ; (FC14) arg#2: C (Track no.) 002B 00 DB $00 ; (FC15) arg#3: H (Head no.) 002C 01 DB $01 ; (FC16) arg#4: R (Sector no.) 002D 02 DB $02 ; (FC17) arg#5: N (Bytes/sector) *** 2 means 512 bytes/sector=128*2^N *** 002E 09 DB $09 ; (FC18) arg#6: EOT (Last sector no. of a track) *** 9 sectors/track *** 002F 20 DB $20 ; (FC19) arg#7: GPL (Gap 3 Length, betw sectors) 0030 FF DB $FF ; (FC1A) arg#8: DTL (Data Length, no.of bytes to be rd/wr into sector) =FF if N!=0 0031 FF DB $FF 0032 00 DB $00 ; (FC1C) result byte#1: ST0 0033 00 DB $00 ; (FC1D) result byte#2: ST1 / PCN 0034 00 DB $00 ; (FC1E) result byte#3: ST2 0035 00 DB $00 ; (FC1F) result byte#4: C 0036 00 DB $00 ; (FC20) result byte#5: H 0037 00 DB $00 ; (FC21) result byte#6: R 0038 00 DB $00 ; (FC22) result byte#7: N 0039 00 DB $00 ; 003A 00 DB $00 003B F3 DI 003C 2100FC LD HL,$FC00 003F F9 LD SP,HL ; stack at FC00 0040 ED5E IM 2 0042 7C LD A,H ; upper half of CTC interrupt table start address (FC)... 0043 ED47 LD I,A ; ...is stored in register I (see Z80 docs) 0045 7D LD A,L ; lower half of CTC interrupt table start address (00)... 0046 D3E3 OUT ($E3),A ; ... is sent to CTC channel 0 ; int. vectors at (FC00-FC01) for CTC0, (FC02-FC03) for CTC1 ; (FC04-FC05) for CTC2, (FC06-FC07) for CTC3 0048 3EFF LD A,$FF ; data for CTC0 on next line: set CTC0 to counter mode and enable CTC0 interrupts 004A D3E3 OUT ($E3),A ; write FF to CTC channel 0 (Enable Interrupt, Counter Mode, ; Rising Edge, Time Const. Follows, Reset, Control). ; MEANING: Reset, Enable Interrupts for Channel 0, a Time Constant follows. 004C 3E01 LD A,$01 ; time constant for CTC0 on next line: generate INT for each byte transferred from 8272 to µP 004E D3E3 OUT ($E3),A ; write 01 to CTC channel 0 ; MEANING: Time Constant byte (=01, for 1 byte read). 0050 3E7B LD A,$7B ; data for CTC3 on next line: disable int, Counter Mode, rising edge, ; No Time Const. Follows, Software Reset 0052 D3FB OUT ($FB),A ; write 7B to CTC channel 3 (disable interrupt) 0054 217FFC LD HL,$FC7F ; CTC0 interrupt vector (for CTC INT. ROUTINE #2) to be set by CTC_1+2_INIT next 0057 CD82FC CALL $FC82 ; call CTC_1+2_INIT 005A CDC5FC CALL $FCC5 ; call 8272_RD (make sure 8272 is finished with any possible previous command) 005D 2111FC LD HL,$FC11 ; start addr for arg bytes of a Specify command (0027 within this code) 0060 010303 LD BC,$0303 ; B=03 for 3 command bytes, C=03 for 8272 Specify opcode 0063 CDA5FC CALL $FCA5 ; call 8272_WR (send a Specify command to 8272) 0066 D9 EXX ; <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <---| 0067 010402 LD BC,$0204 ; B=02 for 2 command bytes, C=04 for 8272 Sense Drive Status opcode | 006A CDA2FC CALL $FCA2 ; call 8272_WR_HL (send a Sense Drive Status command to 8272, arg bytes from FC13) | 006D CDC5FC CALL $FCC5 ; call 8272_RD (reads command result, returns ST3 in register A) | 0070 CB6F BIT 5,A ; test bit 5 of ST3 (RDY), should be 1(?) if READY | 0072 D9 EXX ; | 0073 2005 JR NZ,$007A ; if crt drive# is READY --->| | 0075 34 INC (HL) ; HL=FC13 points to first command arg (drive# and head#), this increments drive# | 0076 CB96 RES 2,(HL) ; set head# to 0 | | 0078 18EC JR $0066 ; ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> --->| 007A CDE7FC CALL $FCE7 ; call TRACK_READ <--- <-----| reads track 00 both sides 007D CDE7FC CALL $FCE7 ; call TRACK_READ reads track 01 both sides 0080 C30000 JP $0000 ; runs the code at the beginning of sector 1 track 00 side 0 0083 EDA2 INI ; ######## CTC INT. ROUTINE #3 (FC6D) ####### 0085 FB EI ; this routine reads bytes from FDD 0086 ED4D RETI ; ######## CTC INT. ROUTINE #1 (FC72) ####### ; this is executed when CTC2 generates an interrupt, which ; happens after one full track has been read (both sides, ; 9 sectors each side, 18 sectors in total) 0088 E5 PUSH HL 0089 2A02FC LD HL,($FC02) ; \ overwrite current CTC0 int. vector in (FC00-FC01) 008C 2200FC LD ($FC00),HL ; / with CTC1 int. vector from (FC02-FC03) 008F 2108FC LD HL,$FC08 ; location FC08 used as a flag: 0092 36FF LD (HL),$FF ; (FC08)=FF right after a track has been completely read 0094 E1 POP HL 0095 FB EI ; ######## CTC INT. ROUTINE #2 (FC7F) ####### 0096 ED4D RETI ; this int. routine does nothing ; ######## CTC_1+2_INIT (FC82) ######### ; inputs: HL=CTC0 interrupt vector 0098 F3 DI 0099 2200FC LD ($FC00),HL ; set CTC0 interrupt vector to contents of HL 009C 3E7F LD A,$7F ; data for CTC1 on next line: disable int, Counter Mode, rising edge, ; Time Const. Follows, Software Reset 009E D3EB OUT ($EB),A ; write 7F to CTC channel 1 00A0 3A0FFC LD A,($FC0F) ; time constant for CTC channel 1 00A3 D3EB OUT ($EB),A ; write time constant to CTC channel 1 00A5 3EFF LD A,$FF ; data for CTC2 on next line: enable int, Counter Mode, rising edge, ; Time Const. Follows, Software Reset 00A7 D3F3 OUT ($F3),A ; write 7F to CTC channel 2 00A9 3A10FC LD A,($FC10) ; time constant for CTC channel 2 00AC D3F3 OUT ($F3),A ; write time constant to CTC channel 2 00AE C9 RET ; ######## 8272_POLL (FC99) ######### 00AF DBF5 IN A,($F5) ; read 8272 Status Register | this routine polls the 8272 Status Register 00B1 CB7F BIT 7,A ; test bit 7 (RQM) | until 8272 is ready to send or receive 00B3 28FA JR Z,$00AF ; if bit 7 = 0 read 8272 Status Register again | data to or from the CPU. When ready (RQM=1) 00B5 CB77 BIT 6,A ; test bit 6 | bit 6 is tested (DIO, 0=receive/1=send) 00B7 C9 RET ; ######## 8272_WR_HL (FCA2) ######### 00B8 2113FC LD HL,$FC13 ; routine below with arg bytes taken from FC13 ; ######## 8272_WR (FCA5) ######### ; send a command to 8272 ; inputs: HL=start addr of bytes to be sent (command args) ; C=first byte to be sent (command opcode) ; B=nr of command bytes (opcode+args) 00BB DBF5 IN A,($F5) ; <--- <--- <--- <--- <---| read 8272 Status Register 00BD CB67 BIT 4,A ; test bit 4 (FDC Busy) | 00BF 20FA JR NZ,$00BB ; ---> ---> ---> ---> --->| repeat if FDC busy 00C1 1802 JR $00C5 ; ---> ---> --->| 00C3 4E LD C,(HL) ; <--- <--- <---- <--- <--- <---| 00C4 23 INC HL ; | | 00C5 F3 DI ; <--- <--- <---| | 00C6 CD99FC CALL $FC99 ; call 8272_POLL | 00C9 C4D7FC CALL NZ,$FCD7 ; call CPM_TO_COBRA if 8272 to send data 00CC 59 LD E,C ; | 00CD 0EFD LD C,$FD ; | 00CF ED59 OUT (C),E ; send byte to 8272 Data Reg | 00D1 10F0 DJNZ $00C3 ; ---> ---> ---> ---> ---> ---->| 00D3 FB EI 00D4 C9 RET ; ######## 8272_SIS (FCBF) ######## 00D5 010801 LD BC,$0108 ; B=01 for 1 command bytes, C=08 opcode for Sense Interrupt Status 00D8 CDA5FC CALL $FCA5 ; call 8272_WR (send Sense Interrupt Status command to 8272) ; ######## 8272_RD (FCC5) ######### ; reads last command result bytes from 8272 ; outputs: A=first result byte ; (FC1C-FC22)=the max. 7 result bytes in order 00DB 211CFC LD HL,$FC1C ; start address to store 8272 command result bytes 00DE 0608 LD B,$08 ; counter (8 bytes to read from 8272) 00E0 CD99FC CALL $FC99 ; call 8272_POLL <--- <--- <----| 00E3 2813 JR Z,$00F8 ; ---> ---> --->|if all result bytes are read, exit (normal exit) 00E5 36FF LD (HL),$FF ; | | 00E7 DBFD IN A,($FD) ; read 8272 Data| Register | 00E9 77 LD (HL),A ; store result | | 00EA 23 INC HL ; increment storage pointer | 00EB 10F3 DJNZ $00E0 ; ---> ---> --------> ---> ---->| 00ED F3 DI ; ######## CPM_TO_COBRA (FCD7) ######## if 8 result bytes read and still reading, exit (error) 00EE AF XOR A ; | A=00 00EF 6F LD L,A ; | 00F0 67 LD H,A ; | HL=0000 (jump address) 00F1 F6C1 OR $C1 ; | A=C1 00F3 D3FE OUT ($FE),A ; | set SO=1, O6=1, border=blue 00F5 ED4F LD R,A ; | set bit 7 of R to 1 (change to startup config) 00F7 E9 JP (HL) ; | jump to 0000 in startup config 00F8 211CFC LD HL,$FC1C ; <--- <--- <---| 00FB 7E LD A,(HL) ; return with first result byte in A 00FC C9 RET ; ######## TRACK_READ (FCE7) ######### ; reads one track both sides (9 sectors/side, 18 sectors in total) 00FD 010F03 LD BC,$030F ; B=03 for 3 command bytes, C=0F opcode for Seek command 0100 CDA2FC CALL $FCA2 ; call 8272_WR_HL (Seek command with args from FC13) 0103 CDBFFC CALL $FCBF ; call 8272_SIS (returns first result byte (ST0) in A) <--- <--- <--- <--| 0106 CB6F BIT 5,A ; test bit 5 of first result byte ST0 (Seek End bit, if 1 Seek ended ok) | 0108 28F9 JR Z,$0103 ; if Seek not ended, repeat SIS ---> ---> ---> ---> ---> ---> ---> --->| 010A E650 AND $50 ; test bits 6 and 4 (Abnorm. Termination/Equipment Check/Track00 not reached) 010C C4D7FC CALL NZ,$FCD7 ; if any of above errors, CPM_TO_COBRA 010F CDBFFC CALL $FCBF ; call 8272_SIS (returns first result byte (ST0) in A) 0112 FE80 CP $80 ; check if invalid command (SIS after SIS should give ST0=80, invalid command) 0114 20F9 JR NZ,$010F ; if ST0 not 80, go back 2 lines (repeat SIS) 0116 DBF5 IN A,($F5) ; read 8272 Status Register <---| 0118 E60F AND $0F ; test bits 0-3 (FDD 0-3 Busy) | 011A 20FA JR NZ,$0116 ; if any drive busy --> ---> -->| 011C 0603 LD B,$03 ; counter for max. 3 loops to be executed next 011E D9 EXX ; <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <----| 011F 014A02 LD BC,$024A ; B=02 for 2 command bytes, C=4A opcode for Read ID command in MFM mode | 0122 CDA2FC CALL $FCA2 ; call 8272_WR_HL (send Read ID command with arg from (FC13)) | 0125 CDC5FC CALL $FCC5 ; call 8272_RD (returns ST0 in A) | 0128 E6C0 AND $C0 ; test bits 6, 7 (normal termination if both =0) | 012A D9 EXX ; | 012B 2805 JR Z,$0132 ; --->| if normal termination skip next 2 lines | 012D 10EF DJNZ $011E ; ------> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ->| 012F CDD7FC CALL $FCD7 ; | CPM_TO_COBRA 0132 060A LD B,$0A ; <---| B as counter for max 10 lops next 0134 C5 PUSH BC ; <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <-| 0135 AF XOR A ; location FC08 used as a flag: | 0136 3208FC LD ($FC08),A ; =00 right before and during track reading | 0139 216DFC LD HL,$FC6D ; CTC0 interrupt vector to be used next (for CTC INT. ROUTINE #3 - saves FDD bytes) | 013C CD82FC CALL $FC82 ; call CTC_1+2_INIT | 013F 01C609 LD BC,$09C6 ; B=09 for 9 command bytes, C=C6 opcode for Read Data (MT, MFM) on next line | 0142 CDA2FC CALL $FCA2 ; call 8272_WR_HL (send a Read Data (MT, MFM) to 8272) which leaves C=FD | 0145 2A09FC LD HL,($FC09) ; HL=storage start address for data read from disk (0000 to begin, 2400 after 1 track) | 0148 76 HALT ; wait for first interrupt from CTC <--- <--- <-| ## one interrupt per byte read, | 0149 DBF5 IN A,($F5) ; read 8272 Main Status Register | ## bytes read by INI from (C)=(FD) | 014B E620 AND $20 ; test bit 5 (Non-DMA, 1 during exec in Non-DMA,| 0 when exec finished) | 014D 20F9 JR NZ,$0148 ; if exec not finished yet ---> ---> ---> ----->| | 014F 220DFC LD ($FC0D),HL ; save current storage address for data read from disk | 0152 217FFC LD HL,$FC7F ; CTC0 interrupt vector to be used next (for CTC INT. ROUTINE #2 - does nothing) | 0155 CD82FC CALL $FC82 ; call CTC_1+2_INIT | 0158 CDC5FC CALL $FCC5 ; call 8272_RD (after this HL=FC1C) | 015B 3A08FC LD A,($FC08) ; location FC08 used as a flag for track reading | 015E B7 OR A 015F C1 POP BC 0160 2805 JR Z,$0167 ; ------>| if track reading in progress skip 3 lines and restart loop | 0162 7E LD A,(HL) ; | (HL)=(FC1C)=first result byte (ST0) of the 8272 Read Data command | 0163 E6D8 AND $D8 ; | test bits 7 6 4 3 (Interrupt Code, Equipment Check, Not Ready) | 0165 2805 JR Z,$016C ; ---> ---> ---> ---> ---> ---> ---> ---> --->| if none of above errors | 0167 10CB DJNZ $0134 ; <------|---> ---> ---> ---> ---> ---> --->---> ---> ---> ---> ---> ---> ---> ---> ---->| 0169 CDD7FC CALL $FCD7 ; call CPM_TO_COBRA | 016C 2114FC LD HL,$FC14 ; storage address for current track no. <-----| 016F 34 INC (HL) ; increment current track number 0170 2A0BFC LD HL,($FC0B) ; copy the value of storage addr for second system track... 0173 2209FC LD ($FC09),HL ; ...over the value of current storage addr 0176 C9 RET 0177 E9 JP (HL) 0178 211CFC LD HL,$FC1C 017B 7E LD A,(HL) 017C C9 RET 017D 010F03 LD BC,$030F 0180 E5 DB $E5 ; unused portion of the sector (filled with E5 when formatted) 0181 E5 DB $E5 0182 E5 DB $E5 0183 E5 DB $E5 0184 E5 DB $E5 0185 E5 DB $E5 0186 E5 DB $E5 0187 E5 DB $E5 0188 E5 DB $E5 0189 E5 DB $E5 018A E5 DB $E5 018B E5 DB $E5 018C E5 DB $E5 018D E5 DB $E5 018E E5 DB $E5 018F E5 DB $E5 0190 E5 DB $E5 0191 E5 DB $E5 0192 E5 DB $E5 0193 E5 DB $E5 0194 E5 DB $E5 0195 E5 DB $E5 0196 E5 DB $E5 0197 E5 DB $E5 0198 E5 DB $E5 0199 E5 DB $E5 019A E5 DB $E5 019B E5 DB $E5 019C E5 DB $E5 019D E5 DB $E5 019E E5 DB $E5 019F E5 DB $E5 01A0 E5 DB $E5 01A1 E5 DB $E5 01A2 E5 DB $E5 01A3 E5 DB $E5 01A4 E5 DB $E5 01A5 E5 DB $E5 01A6 E5 DB $E5 01A7 E5 DB $E5 01A8 E5 DB $E5 01A9 E5 DB $E5 01AA E5 DB $E5 01AB E5 DB $E5 01AC E5 DB $E5 01AD E5 DB $E5 01AE E5 DB $E5 01AF E5 DB $E5 01B0 E5 DB $E5 01B1 E5 DB $E5 01B2 E5 DB $E5 01B3 E5 DB $E5 01B4 E5 DB $E5 01B5 E5 DB $E5 01B6 E5 DB $E5 01B7 E5 DB $E5 01B8 E5 DB $E5 01B9 E5 DB $E5 01BA E5 DB $E5 01BB E5 DB $E5 01BC E5 DB $E5 01BD E5 DB $E5 01BE E5 DB $E5 01BF E5 DB $E5 01C0 E5 DB $E5 01C1 E5 DB $E5 01C2 E5 DB $E5 01C3 E5 DB $E5 01C4 E5 DB $E5 01C5 E5 DB $E5 01C6 E5 DB $E5 01C7 E5 DB $E5 01C8 E5 DB $E5 01C9 E5 DB $E5 01CA E5 DB $E5 01CB E5 DB $E5 01CC E5 DB $E5 01CD E5 DB $E5 01CE E5 DB $E5 01CF E5 DB $E5 01D0 E5 DB $E5 01D1 E5 DB $E5 01D2 E5 DB $E5 01D3 E5 DB $E5 01D4 E5 DB $E5 01D5 E5 DB $E5 01D6 E5 DB $E5 01D7 E5 DB $E5 01D8 E5 DB $E5 01D9 E5 DB $E5 01DA E5 DB $E5 01DB E5 DB $E5 01DC E5 DB $E5 01DD E5 DB $E5 01DE E5 DB $E5 01DF E5 DB $E5 01E0 E5 DB $E5 01E1 E5 DB $E5 01E2 E5 DB $E5 01E3 E5 DB $E5 01E4 E5 DB $E5 01E5 E5 DB $E5 01E6 E5 DB $E5 01E7 E5 DB $E5 01E8 E5 DB $E5 01E9 E5 DB $E5 01EA E5 DB $E5 01EB E5 DB $E5 01EC E5 DB $E5 01ED E5 DB $E5 01EE E5 DB $E5 01EF E5 DB $E5 01F0 E5 DB $E5 01F1 E5 DB $E5 01F2 E5 DB $E5 01F3 E5 DB $E5 01F4 E5 DB $E5 01F5 E5 DB $E5 01F6 E5 DB $E5 01F7 E5 DB $E5 01F8 E5 DB $E5 01F9 E5 DB $E5 01FA E5 DB $E5 01FB E5 DB $E5 01FC E5 DB $E5 01FD E5 DB $E5 01FE E5 DB $E5 01FF E5 DB $E5